/**
 * 	 Copyright (c) 2008, 2009 Lukas Zaruba
 * 
 *   This file is part of UniAnalyzer (Universal Analyzer).
 *
 *   UniAnalyzer is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   UniAnalyzer is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with UniAnalyzer. If not, see <http://www.gnu.org/licenses/>.
 */

package net.zarubsys.unianalyzer.dataviews.lpt.table.editor;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Locale;

import net.zarubsys.unianalyzer.dataminers.lpt.pin.CustomizedPin;
import net.zarubsys.unianalyzer.dataminers.lpt.results.IResult;
import net.zarubsys.unianalyzer.dataminers.lpt.triggers.TriggerDescription;
import net.zarubsys.unianalyzer.dataminers.lpt.utils.Constants;
import net.zarubsys.unianalyzer.dataviews.lpt.table.dataProvider.TableDataProvider;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IPathEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

public class TableEditor extends EditorPart {

	private Text date;
	private Text address;
	private Text desiredFreq;
	private Table table;
	
	private MenuItem timeUnitsS;
	private MenuItem timeUnitsMs;
	private MenuItem timeUnitsNs;
	private MenuItem valueFormsDec;
	private MenuItem valueFormsHex;
	private MenuItem valueFormsBin;
	
	private IResult result;
	
	private DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.getDefault());
	private static final int PAGE_SIZE = 64;
	private Text realFreq;
	private Label triggerPinDescription;
	private Label triggerEdgeDescription;
	private int tableStyle;
	private int tableTime;
	private TableColumn timeColumn;
	private TableColumn valueColumn;
	
	private static final Logger log = Logger.getLogger(TableEditor.class);

	@Override
	public void doSave(IProgressMonitor monitor) {
		
	}

	@Override
	public void doSaveAs() {
		// it is not allowed
	}

	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		setSite(site);
		if (!(input instanceof IPathEditorInput)) {
			throw new PartInitException("Invalid input: Must be IPathEditorInput");
		} 
		setInput(input);
		
		IPathEditorInput pathInput = (IPathEditorInput) input;
		result = getResult(pathInput);
		setPartName(pathInput.getName());
	}
	
	private void setupValues(IResult result) {
		date.setText(dateFormat.format(result.getDateOfCreation()));
		int addresValue = result.getAddress();
		String addresText = "0x" + Integer.toHexString(addresValue) + " (" + String.valueOf(addresValue) + ")";
		address.setText(addresText);
		desiredFreq.setText(String.valueOf(result.getDesiredFrequency()) + " " + result.getDesiredFrequencyUnits());
		
		float realFrequency = result.getRealFrequency();
		String realFrequencyUnits = "Hz";
		if (realFrequency > 999) {
			realFrequency = Math.round((realFrequency / 1000) * 100);
			realFrequency /= 100;
			realFrequencyUnits = "kHz";
		}	
		String formattedFrequency = NumberFormat.getInstance().format(realFrequency);
		realFreq.setText(formattedFrequency + " " + realFrequencyUnits);
		TriggerDescription triggerDescription = result.getTriggerDescription();
		boolean triggerDescPresented = triggerDescription != null;
		if (triggerDescPresented) {
			CustomizedPin pin = triggerDescription.getPin();
			triggerPinDescription.setText(pin.getCustomizedLabel());
			String risingEdgeDesc = triggerDescription.isRisingEdge() ? "Rising Edge" : "Falling Edge";
			triggerEdgeDescription.setText(risingEdgeDesc);
		} else {
			triggerPinDescription.setText("Not Used");
		}
		
		tableStyle = TableDataProvider.DECIMAL;
		tableTime = TableDataProvider.SECOND;
		setTimeColumnText(Constants.timeUnitsSecDescription);
		setValueColumnText(Constants.valueFormDecDescription);
		
		timeUnitsS.setSelection(true);
		valueFormsDec.setSelection(true);
		table.setItemCount(result.getSamplesCount());
	}

	private IResult getResult(IPathEditorInput pathInput) throws PartInitException {
		File file = pathInput.getPath().toFile();
		ObjectInputStream ois = null;
		IResult result = null;
		try {
			ois = new ObjectInputStream(new FileInputStream(file));
			result = (IResult) ois.readObject();
		} catch (FileNotFoundException e) {
			log.error("Error reading measuring result.", e);
			throw new PartInitException("Error reading measuring result.", e);
		} catch (IOException e) {
			log.error("Error reading measuring result.", e);
			throw new PartInitException("Error reading measuring result.", e);
		} catch (ClassNotFoundException e) {
			log.error("Error reading measuring result.", e);
			throw new PartInitException("Error reading measuring result.", e);
		} finally {
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					log.error("Error closing measuring result input stream.", e);
					throw new PartInitException("Error closing measuring result input stream.", e);
				}
			}
		}
		return result;
	}

	@Override
	public boolean isDirty() {
		return false;
	}

	@Override
	public boolean isSaveAsAllowed() {
		return false;
	}

	@Override
	public void createPartControl(Composite parent) {
		Label label;
		GridData gd;
		
		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(1, false));
		
		// top
		Composite metaData = new Composite(composite, SWT.NONE);
		metaData.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		metaData.setLayout(new GridLayout(1, false));
		
		Group metadataGroup = new Group(metaData, SWT.NONE);
		metadataGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		metadataGroup.setLayout(new GridLayout(3, false));
		metadataGroup.setText("Metadata");
		
		
		// top left
		Composite metaDataLeft = new Composite(metadataGroup, SWT.NONE);
		metaDataLeft.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, true));
		metaDataLeft.setLayout(new GridLayout(2, false));
		
		label = new Label(metaDataLeft, SWT.NONE);
		label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
		label.setText("Date:");
		
		date = new Text(metaDataLeft, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
		date.setEnabled(false);
		gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
		gd.widthHint = 120;
		date.setLayoutData(gd);
		
		label = new Label(metaDataLeft, SWT.NONE);
		label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
		label.setText("Address:");
		
		address = new Text(metaDataLeft, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
		gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
		gd.widthHint = 120;
		address.setLayoutData(gd);
		address.setEnabled(false);
		
		// top middle
		Composite metaDataMiddle = new Composite(metadataGroup, SWT.NONE);
		metaDataMiddle.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, true));
		metaDataMiddle.setLayout(new GridLayout(2, false));
		
		label = new Label(metaDataMiddle, SWT.NONE);
		label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
		label.setText("Desired freq.:");
		
		desiredFreq = new Text(metaDataMiddle, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
		gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
		gd.widthHint = 100;
		desiredFreq.setLayoutData(gd);
		desiredFreq.setEnabled(false);
		
		label = new Label(metaDataMiddle, SWT.NONE);
		label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
		label.setText("Real freq.:");
		
		realFreq = new Text(metaDataMiddle, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
		gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
		gd.widthHint = 100;
		realFreq.setLayoutData(gd);
		realFreq.setEnabled(false);
		
		// top right
		Composite metaDataRight = new Composite(metadataGroup, SWT.NONE);
		metaDataRight.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, true));
		metaDataRight.setLayout(new GridLayout(1, false));
		
		label = new Label(metaDataRight, SWT.NONE);
		label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
		label.setText("Trigger:");
		
		triggerPinDescription = new Label(metaDataRight, SWT.NONE);
		gd = new GridData(SWT.BEGINNING, SWT.BOTTOM, false, false);
		label.setLayoutData(gd);
		
		triggerEdgeDescription = new Label(metaDataRight, SWT.NONE);
		triggerEdgeDescription.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
		
		// bottom
		Composite data = new Composite(composite, SWT.NONE);
		data.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		data.setLayout(new GridLayout(1, true));
		
		table = new Table(data, SWT.SINGLE | SWT.BORDER | SWT.VIRTUAL | SWT.V_SCROLL | SWT.FULL_SELECTION);
		gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		gd.heightHint = 1;
		table.setLayoutData(gd);
		table.setLinesVisible(true);
		table.setHeaderVisible(true);
		table.addListener (SWT.SetData, new Listener () {
			public void handleEvent(Event event) {
				TableDataProvider provider = new TableDataProvider(result, tableStyle, tableTime);
				TableItem item = (TableItem) event.item;
				int index = table.indexOf(item);
				int start = index / PAGE_SIZE * PAGE_SIZE;
				int end = Math.min(start + PAGE_SIZE, table.getItemCount());
				for (int i = start; i < end; i++) {
					item = table.getItem (i);
					item.setText(provider.getRowData(i));
				}
				for (int i = 0; i < table.getColumnCount(); i++) { // TODO does it belong here?
					table.getColumn(i).pack();
				}
			}
		});

		
		TableColumn orderColumn = new TableColumn(table, SWT.NONE);
		orderColumn.setText("Order");
		
		timeColumn = new TableColumn(table, SWT.NONE);
		timeColumn.setText("Time");
		timeColumn.setToolTipText("Click right button into the table to change time units");
		
		valueColumn = new TableColumn(table, SWT.NONE);
		valueColumn.setText("Value");
		valueColumn.setToolTipText("Click right button into the table to change value style");
		
		Menu headerMenu = new Menu(data);

		final MenuItem timeUnitsItem = new MenuItem(headerMenu, SWT.CASCADE);
		timeUnitsItem.setText("Time units");
		final MenuItem valueFormItem = new MenuItem(headerMenu, SWT.CASCADE);
		valueFormItem.setText("Value form");
		
		TimeUnitsSelectionListener timeUnitsSL = new TimeUnitsSelectionListener();
		
		Menu timeUnitsSubmenu = new Menu(timeUnitsItem);
		timeUnitsS = new MenuItem(timeUnitsSubmenu, SWT.RADIO);
		timeUnitsS.setText(Constants.timeUnitsSecDescription);
		timeUnitsS.addSelectionListener(timeUnitsSL);
		timeUnitsMs = new MenuItem(timeUnitsSubmenu, SWT.RADIO);
		timeUnitsMs.setText(Constants.timeUnitsMiliSecDescription);
		timeUnitsMs.addSelectionListener(timeUnitsSL);
		timeUnitsNs = new MenuItem(timeUnitsSubmenu, SWT.RADIO);
		timeUnitsNs.setText(Constants.timeUnitsMicroSecDescription);
		timeUnitsNs.addSelectionListener(timeUnitsSL);
		timeUnitsItem.setMenu(timeUnitsSubmenu);
		
		ValueFormSelectionListener valueFormSL = new ValueFormSelectionListener();
		
		Menu valueFormsSubmenu = new Menu(valueFormItem);
		valueFormsDec = new MenuItem(valueFormsSubmenu, SWT.RADIO);
		valueFormsDec.setText(Constants.valueFormDecDescription);
		valueFormsDec.addSelectionListener(valueFormSL);
		valueFormsHex = new MenuItem(valueFormsSubmenu, SWT.RADIO);
		valueFormsHex.setText(Constants.valueFormHexDescription);
		valueFormsHex.addSelectionListener(valueFormSL);
		valueFormsBin = new MenuItem(valueFormsSubmenu, SWT.RADIO);
		valueFormsBin.setText(Constants.valueFormBinDescription);
		valueFormsBin.addSelectionListener(valueFormSL);
		valueFormItem.setMenu(valueFormsSubmenu);
		
		table.setMenu(headerMenu);
		Display.getCurrent().asyncExec(new Runnable() {

			public void run() {
				setupValues(result);
			}
			
		});
		
		for (int i = 0; i < table.getColumnCount(); i++) {
			table.getColumn(i).pack();
		}
	}
	
	private class TimeUnitsSelectionListener implements SelectionListener {

		public void widgetDefaultSelected(SelectionEvent e) {
			widgetSelected(e);
		}

		public void widgetSelected(SelectionEvent e) {
			if (e.widget instanceof MenuItem) {
				if (!((MenuItem) e.widget).getSelection()) return;
			} else {
				return;
			}
			
			if (e.widget == timeUnitsS) {
				tableTime = TableDataProvider.SECOND;
				setTimeColumnText(Constants.timeUnitsSecDescription);
			} else if (e.widget == timeUnitsMs) {
				tableTime = TableDataProvider.MILISECOND;
				setTimeColumnText(Constants.timeUnitsMiliSecDescription);
			} else if (e.widget == timeUnitsNs) {
				tableTime = TableDataProvider.MICROSECOND;
				setTimeColumnText(Constants.timeUnitsMicroSecDescription);
			}
			table.clearAll();
		}
		
		
	}
	
	private void setTimeColumnText(String value) {
		timeColumn.setText("Time (" + value + ")");
	}
	
	private void setValueColumnText(String value) {
		valueColumn.setText("Value (" + value + ")");
	}
	
	private class ValueFormSelectionListener implements SelectionListener {

		public void widgetDefaultSelected(SelectionEvent e) {
			widgetSelected(e);
		}

		public void widgetSelected(SelectionEvent e) {
			if (e.widget instanceof MenuItem) {
				if (!((MenuItem) e.widget).getSelection()) return;
			} else {
				return;
			}
			
			if (e.widget == valueFormsDec) {
				tableStyle = TableDataProvider.DECIMAL;
				setValueColumnText(Constants.valueFormDecDescription);
			} else if (e.widget == valueFormsHex) {
				tableStyle = TableDataProvider.HEX;
				setValueColumnText(Constants.valueFormHexDescription);
			} else if (e.widget == valueFormsBin) {
				tableStyle = TableDataProvider.BINARY;
				setValueColumnText(Constants.valueFormBinDescription);
			}
			table.clearAll();
		}
		
		
	}

	@Override
	public void setFocus() {
		table.setFocus();
	}

}


/*
 * $Log$
 */